package com.qf.ability.test;

import com.qf.ability.search.application.SearchApplication;
import com.qf.ability.test.entity.Goods;
import com.qf.ability.test.service.IGoodsService;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.query.functionscore.FieldValueFactorFunctionBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.range.RangeAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@SpringBootTest(classes = SearchApplication.class)
@ComponentScan("com.qf.ability.test")
@RunWith(SpringRunner.class)
public class SearchTestApplication {

    @Autowired
    private IGoodsService goodsService;

    @Autowired
    private ElasticsearchRestTemplate template;

    @Test
    public void test() {
        System.out.println("创建索引库");
        boolean flag = goodsService.createIndex();
        System.out.println("创建结果：" + flag);

        boolean mapping = goodsService.createMapping();
        System.out.println("创建映射类型的结果：" + mapping);

        Goods goods = new Goods();
        goods.setId(1);
        goods.setTitle("美的滚筒洗衣机");
        goods.setPrice(999.99);
        goods.setImage("http://xxxxx/xxxx/xxxx");
        goods.setCreataTime(new Date());
        goods.setInfo("这是一个性价比很高的洗衣机，洗衣机中的直升机");
        goodsService.addGoods(goods);

        Goods goods2 = new Goods();
        goods2.setId(2);
        goods2.setTitle("美的波轮电视机");
        goods2.setPrice(2999.99);
        goods2.setImage("http://xxxxx/xxxx/xxxx");
        goods2.setCreataTime(new Date());
        goods2.setInfo("这是一个性价比很高的电视机，电视机中的直升机");
        goodsService.addGoods(goods2);

//        goodsService.updateGoods(1, "price", 9.9);

//        goodsService.deteleGoods(1);
    }

    /**
     * 通过JavaAPI调用ES实现搜索
     */
    @Test
    public void testSearch() {
        //term搜索
        TermQueryBuilder termQuery = QueryBuilders.termQuery("title", "美的");
        //match搜索
        MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("title", "美的洗衣机");
        //multi_match查询
        MultiMatchQueryBuilder multiMatchQueryBuilder =
                QueryBuilders.multiMatchQuery("美的洗衣机")
                        .field("title", 20)
                        .field("info", 1);
        //range
        RangeQueryBuilder price = QueryBuilders.rangeQuery("price").gte(1000).lt(5000);


        //        //bool复合查询
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
//                .must(QueryBuilders.matchQuery())
//                .must(QueryBuilders.termQuery())
//                .should(QueryBuilders.rangeQuery())
//                .mustNot(QueryBuilders.boolQuery())
//                .minimumShouldMatch(1);
//
//        //boosting查询
//        BoostingQueryBuilder boostingQueryBuilder = QueryBuilders.boostingQuery(QueryBuilders.rangeQuery(), QueryBuilders.fuzzyQuery())
//                .negativeBoost(0.5f);

        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();


        //地理坐标的搜索
//        QueryBuilders.geoDistanceQuery("location")
//                .point(22,114)
//                .distance(10, DistanceUnit.KILOMETERS);
//
//        QueryBuilders.geoBoundingBoxQuery("location")
//                .setCorners(new GeoPoint(22,114), new GeoPoint(22,114));
//
//        QueryBuilders.geoPolygonQuery("location", List<GeoPoint>);

        //添加按照距离排序
//        GeoDistanceOrder location = new GeoDistanceOrder("location", new GeoPoint(22, 114));
//        location
//                .with(Sort.Direction.ASC)
//                .with(GeoDistanceOrder.DistanceType.plane)
//                .withUnit("km");
//        query.addSort(Sort.by(location));

        //funcation_score 加强评分
        List<FunctionScoreQueryBuilder.FilterFunctionBuilder> functionBuilders = new ArrayList<>();
        //添加多个评分函数
        functionBuilders.add(
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                        new FieldValueFactorFunctionBuilder("price").setWeight(0.0005f)));
//        functionBuilders.add(...);
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(
                QueryBuilders.matchAllQuery(),
                functionBuilders.toArray(new FunctionScoreQueryBuilder.FilterFunctionBuilder[0])
        );
        functionScoreQueryBuilder.boostMode(CombineFunction.MULTIPLY);//加强评分和原始评分的合并函数
        functionScoreQueryBuilder.scoreMode(FunctionScoreQuery.ScoreMode.MULTIPLY);//多个评分函数之间的合并函数


        //创建一个查询对象
        NativeSearchQuery query = new NativeSearchQuery(functionScoreQueryBuilder);
        //添加排序
        query.addSort(Sort.by(Sort.Order.desc("price")));
        //添加高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder
                .field("title")
                .preTags("<font color='red'>")
                .postTags("</font>");
        query.setHighlightQuery(new HighlightQuery(highlightBuilder));
        //添加聚合
        RangeAggregationBuilder rangeAggregationBuilder = new RangeAggregationBuilder("price_group");
        rangeAggregationBuilder.addRange(0, 1000);
        rangeAggregationBuilder.addRange(1000, 2000);
        rangeAggregationBuilder.addRange(2000, Double.MAX_VALUE);

        AvgAggregationBuilder price_group_avg = new AvgAggregationBuilder("price_group_avg");
        price_group_avg.field("price");
        rangeAggregationBuilder.subAggregation(price_group_avg);
        //设置聚合操作
        query.addAggregation(rangeAggregationBuilder);

        SearchHits<Goods> hits = template.search(query, Goods.class);

        //获得搜索出来的聚合结果
        Aggregations aggregations = hits.getAggregations();

        //获得搜索的结果列表
        List<SearchHit<Goods>> searchHits = hits.getSearchHits();
        System.out.println("搜索的结果数量：" + hits.getTotalHits());
        for (SearchHit<Goods> searchHit : searchHits) {
            //SearchHit -> 表示一个查询结果记录（Document）
            Goods goods = searchHit.getContent();
            //获取高亮
            List<String> highlight = searchHit.getHighlightField("title");
            if (!CollectionUtils.isEmpty(highlight)) {
                goods.setTitle(highlight.get(0));
            }

            System.out.println(searchHit.getScore() + " 结果：" + goods);
        }
    }

}